新世代フロントエンド (NOT) フレームワーク ~ SVELTE ~
目次
- ちょっと概要
- みんなの感想
- 今後の展開
- チュートリアル触ってみよう
- TODOアプリ作ってみよう
- 感想
おまけ
- riot.js
svelteとは
フレームワークではなくコンパイラ (Vueっぽく書けるBabel?)
storeはsvelteに含まれている
routerある SSRできる(sapperっていうnext.jsっぽいやつ)
熱い!svelte3をリリースした時の公式ブログのpost
Svelte 3: Rethinking reactivity
みんなの感想
JavaScriptはフレームワークについて考え直すときが来ています(翻訳記事)
読みます
Vue.jsの50倍早いライブラリ!?「Svelte」
テンプレートをコンパイルして、Virtual DOM 形式の UI を持つ Javascript ソースコードを作成する
これによって他のフレームワークでは必要なランタイムが不要となるため高速に動作が可能となる
ReactとVueを改善したSvelteというライブラリーについて
Svelteは速く、軽いです。
ベンチマークでReactの35倍、Vueの50倍速いです。
Svelteはコンパイラーであるため、実質ライブラリーとしての容量は0kbです。
(もちろんコンパイル時に少しはコードが加わりますが)
ふとしたキッカケで Svelte を使ってみた
結論だけいうと、コンパイラなので依存が実質的に何もないし、実際に軽くて早くてコード量が少ないのは事実なので、使い慣れてきたらかなり良さそう。
ただし複数人でコードをいじる場合には、フレームワーク自体のルールがほとんどないので、チーム内での統一ルールなどが無いと扱いにくいかも、特に store 周り
↑と同じかた
Svelteのドキュメントを翻訳してみた
svelteとsapperでwebアプリを作ってherokuにデプロイする(した)方法
大量のオブジェクトを描画したりするスピードが体感的に速い気がする。
ビルドも速い。
非同期通信を上手く扱う仕組みがイケている。
でも pug と typescript が上手く組み込めない。
ちなみに読み方はスヴェルテっぽい。フランス語でシュッとした的な意味らしい。
silloi.icon 発音は英語でもフランス語でも /svɛlt/
/スヴェルト/ の方が近い
でも日本語では最後のeに引っ張られて /スヴェルテ/ が定着しそう
左の男性が "svelte"
https://gyazo.com/78f5b2b60aada21770f823e1f13ac52b
今後の展開
公式サイトより
What about Typescript support?
We have no TS support yet but it's very much planned - v3 was partly about laying the foundation for it.
tutorialを触ってみよう!!
htmlタグの中で変数を使う
code: Hello(html)
<h1>Hello {name}!</h1>
<script>
let name ='world'
</script>
code:img(html)
<script>
let src = 'assets/image.gif';
</script>
<img src={src}>
styleを当てる
svelteコンポーネントはデフォでscoped
code: styling(html)
<style>
p {
color: purple;
font-family: 'Comic Sans MS';
font-size: 2em;
}
</style>
<p>This is a paragraph.</p>
生のHTMLを使う
XSSに注意!
code: rowHTML(html)
<script>
let string = this string contains some <strong>HTML!!!</strong>;
</script>
<p>{@html string}</p>
Reactivity
code:reactivity(html)
<script>
let count = 0;
function handleClick() {
count += 1;
}
</script>
<button>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
computed
code:computed(html)
<script>
let count = 0;
$: doubled = count * 2;
function handleClick() {
count += 1;
}
</script>
<p>{count} doubled is {doubled}</p>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
computedは便利!
Vueのcomputedとwatchが一緒になってるようなもの
code: 便利!!(html)
<script>
let count = 0;
$: {
console.log(the count is ${count});
if (count >= 10) {
alert(I SAID THE COUNT IS ${count});
}
}
function handleClick() {
count += 1;
}
</script>
<button on:click={handleClick}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
配列の変更を感知するために
ダメ
code:pushはだめ(html)
function addNumber() {
numbers.push(numbers.length + 1);
numbers = numbers;
}
OK
code:慣例的なやり方(html)
function addNumber() {
}
code:これでもいける!(html)
function addNumber() {
}
コンポーネント間での通信
Props
code:App.svelte(html)
<script>
import Nested from './Nested.svelte';
</script>
<Nested answer={42}/>
code:Nested.svelte(html)
<script>
export let answer;
</script>
<p>The answer is {answer}</p>
propsの初期値はこんな感じ
code:propsの初期値を設定(html)
<script>
export let answer = 'default value'
</script>
<p>The answer is {answer}</p> // propsが渡ってこなかったら The answer is default value って表示される
Objectを子コンポーネントに渡す
親
code: App.svelte(html)
<script>
import Info from './Info.svelte';
const pkg = {
name: 'svelte',
version: 3,
speed: 'blazing',
};
</script>
<Info name={pkg.name} version={pkg.version} speed={pkg.speed} website={pkg.website}/>
子
code:Info.svelte(html)
<script>
export let name;
export let version;
export let speed;
export let website;
</script>
<p>
The <code>{name}</code> package is {speed} fast.
and <a href={website}>learn more here</a>
</p>
スプレッド演算子を使っても渡せる( ! )
code: App.svelte(html)
<Info {...pkg}/>
子コンポーネントでは$$props.nameみたいにも使える (!?)
code:Info.svelte(html)
<p> { $$props.name } </p>
テンプレートの中でif文を使う
code:App.svelte(html)
<script>
let user = { loggedIn: false };
function toggle() {
user.loggedIn = !user.loggedIn;
}
</script>
{#if user.loggedIn }
<button on:click={toggle}>
Log out
</button>
{/if}
{#if !user.loggedIn }
<button on:click={toggle}>
Log in
</button>
{/if}
if... else を使う
code:if...else(html)
<script>
let user = { loggedIn: false };
function toggle() {
user.loggedIn = !user.loggedIn;
}
</script>
{#if user.loggedIn}
<button on:click={toggle}>
Log out
</button>
{:else}
<button on:click={toggle}>
Log in
</button>
{/if}
#は始まり、/は終わり。 :は真ん中!
ネストされたif文
code:ネストされてる〜(html)
<script>
let x = 7;
</script>
{#if x > 10}
<p>{x} is greater than 10</p>
{:else}
{#if 5 > x}
<p>{x} is less than 5</p>
{:else}
<p>{x} is between 5 and 10</p>
{/if}
{/if}
each文
code:each文(html)
<script>
let cats = [
{ id: 'J---aiyznGQ', name: 'Keyboard Cat' },
{ id: 'z_AbfPXTKms', name: 'Maru' },
{ id: 'OUtn3pvWmpg', name: 'Henri The Existential Cat' }
];
</script>
<h1>The Famous Cats of YouTube</h1>
<ul>
{#each cats as cat}
{cat.name}
</a></li>
{/each}
</ul>
code:indexも返します(html)
{#each cats as cat, i}
{i + 1}: {cat.name}
</a></li>
{/each}
eachで並べたコンポーネントをいじるときはkeyをつけてあげないとバグる
code:keyをつけてあげないとバグる(html)
// App.svelte
<script>
import Thing from './Thing.svelte';
let things = [
{ id: 1, color: '#0d0887' },
{ id: 2, color: '#6a00a8' },
{ id: 3, color: '#b12a90' },
{ id: 4, color: '#e16462' },
{ id: 5, color: '#fca636' }
];
function handleClick() {
things = things.slice(1);
}
</script>
<button on:click={handleClick}>
Remove first thing
</button>
{#each things as thing(thing.id)} // ココ!!
<Thing current={thing.color}/>
{/each}
// Thing.svelte
<script>
// current is updated whenever the prop value changes...
export let current;
// ...but initial is fixed upon initialisation
const initial = current;
</script>
<p>
<span style="background-color: {initial}">initial</span>
<span style="background-color: {current}">current</span>
</p>
promiseもかける!!
code:promise(html)
<script>
let promise = getRandomNumber();
async function getRandomNumber() {
const res = await fetch(tutorial/random-number);
const text = await res.text();
if (res.ok) {
return text;
} else {
throw new Error(text);
}
}
function handleClick() {
promise = getRandomNumber();
}
</script>
<button on:click={handleClick}>
generate random number
</button>
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
rejectされないってときはcatch errorのところを省略できるよ
code:catch errorを省略
{#await promise then value}
<p>the value is {value}</p>
{/await}
Bindings!!
普通のやつ
code:inputにバインド(html)
<script>
let name = 'world';
</script>
<input bind:value={name}>
<h1>Hello {name}!</h1>
入力もしてくれる(v-model)bind:group <input type="checkbox"> or <input type="radio">でしか使えない
code:bind:group(html)
<script>
let number = 1;
</script>
<h1>selected {number}</h1>
<input type="radio" bind:group={number} value={1}> One
<input type="radio" bind:group={number} value={2}> two
<input type="radio" bind:group={number} value={3}> three
ブロックレベル要素へのbinding
code:ブロックレベル要素!(html)
<script>
let w;
let h;
let size = 42;
let text = 'edit me';
</script>
<style>
input { display: block; }
div { display: inline-block; }
</style>
<input type=range bind:value={size}>
<input bind:value={text}>
<p>size: {w}px x {h}px</p>
<div bind:clientWidth={w} bind:clientHeight={h}> // おお!
<span style="font-size: {size}px">{text}</span>
</div>
感想
$とか{#if}の構文とか.svelteファイルの中でのscript, styleの順番とかとか変な感じがするけど、それは慣れてないだけで多分大丈夫。
storeもrouterもSSR等のエコシステムが充実していて本気を感じる。
typescriptに対応したら化けるかも。。?
今まさに進化の途中にあるプロダクトであり、公式のブログを読んでるとワクワクしてくる。情熱を感じる。
ソースコード読んでもっと中身を理解したいと思った。